<?php
/**
 * Created by PhpStorm.
 * User: heitao
 * Date: 2018/5/30
 * Time: 16:12
 */

namespace manniu\model;

use think\Config;
use think\Model;
use manniu\controller\Cache;
use think\Request;
use manniu\tools\Tree;

abstract class Category extends Model
{
    protected $ids = [];
    protected $categorys;
    protected static $cacheKey = 'category';

    // 栏目配置 - 获取器
    public function getSettingAttr($value)
    {
        return mn_string2array($value);
    }

    // 栏目配置 - 修改器
    public function setSettingAttr($value)
    {
        return mn_array2string($value);
    }

    // 会员权限 - 获取器
    public function getPermissionAttr($value)
    {
        return mn_string2array($value);
    }

    // 会员权限 - 修改器
    public function setPermissionAttr($value)
    {
        return mn_array2string($value);
    }

    // 栏目目录 - 修改器
    public function setDirnameAttr($value)
    {
        return str_replace(['/', '-', '_'], '', $value);
    }

    // 是否显示 - 修改器
    public function setShowAttr($value)
    {
        return $value ? 1 : 0;
    }

    /**
     * 获取栏目
     */
    public static function getCategoryAll(){
        $categorys = self::cacheAll();
        if(!$categorys){
            $categorys = self::setCacheAll();
        }
        return $categorys;
    }

    /**
     * 获取所有栏目缓存
     */
    public static function cacheAll(){
        return Cache::get(static::$cacheKey);
    }

    /**
     * 设置所有栏目缓存
     */
    public static function setCacheAll(){
        $categorys = [];
        $result = self::all();
        foreach ($result as $key => $category) {
            $categorys[$category['id']] = $category;
        }
        $categorys = $categorys ? collection($categorys)->toArray() : [];
        Cache::set(static::$cacheKey, $categorys, Config::get('mn_book.category_cache_time'));
        return $categorys;
    }

    /**
     * 树形结构 - select
     * @access public
     * @param int $pid 父栏目ID
     * @param int $build_url option的value设置为url，默认为栏目ID
     * @return string
     */
    public function getTreeOption($pid = 0, $build_url = false)
    {
        $pid = (int)$pid;
        // 查询所有内容
        $result = $this->order(['displayorder' => 'asc', 'id' => 'desc'])->select();
        // 生成树型类需要的数组
        $list = [];
        foreach ($result as $key => $value) {
            $list[$key] = $value->toArray();
            // 生成url
            if ($build_url) {
                $request = Request::instance();
                $list[$key]['url'] = str_replace($request->baseFile(), '', url('book/index/category', ['dirname' => $value->dirname]));
            }
            // 默认选中
            $list[$key]['selected'] = $value->id == $pid ? 'selected' : '';
        }
        // 默认生成树型结构的基本代码
        $str = "<option value='\$id' \$selected>\$spacer \$name</option>";
        if ($build_url) {
            // value设置为url时，生成树型结构的基本代码
            $str = "<option value='\$url' \$selected>\$spacer \$name</option>";
        }

        // 实例化树型类
        $tree = new Tree;
        //设置树型结构所需的数组
        $tree->init($list);
        $data = $tree->getTree(0, $str);
        return $data ? $data : '';
    }

    /**
     * 树形结构 - table
     * @access public
     * @param int $pid 父栏目ID
     * @return string
     */
    public function getTreeTable($pid = 0)
    {
        $pid = (int)$pid;
        // 查询所有内容
        $result = $this->order(['displayorder' => 'asc', 'id' => 'desc'])->select();
        // 实例化树型类
        $tree = new Tree;
        // 设置初始值
        $tree->icon = ['&nbsp;&nbsp;&nbsp;│ ', '&nbsp;&nbsp;&nbsp;├─ ', '&nbsp;&nbsp;&nbsp;└─ '];
        $tree->nbsp = '&nbsp;&nbsp;&nbsp;';
        // 生成树型类需要的数组
        $list = [];
        if ($result) {
            foreach ($result as $key => $value) {
                $list[$key] = $value->toArray();

                $list[$key]['show'] = '';
                $list[$key]['show'] .= '<i class="fa ';
                $list[$key]['show'] .= $value->getAttr('show') ? 'fa-check-circle color_primary' : 'fa-times-circle color_danger';
                $list[$key]['show'] .= '" style="font-size:18px;">';

                $list[$key]['mn_option'] = '<div class="layui-btn-group">';
                $list[$key]['mn_option'] .= '<a class="layui-btn layui-btn-small layui-btn-primary" href="' . url('add', ['pid' => $value->getAttr('id')]) . '"><i class="layui-icon">&#xe654;</i> 添加子类</a>';
                $list[$key]['mn_option'] .= '<a class="layui-btn layui-btn-small layui-btn-primary" href="' . url('edit', ['id' => $value->getAttr('id')]) . '"><i class="layui-icon">&#xe642;</i> 修改</a>';
                $list[$key]['mn_option'] .= '</div>';
            }
        }
        //设置树型结构所需的数组
        $tree->init($list);
        // 生成树型结构的基本代码
        $str = "<tr>
                    <td class='text-center'><input type='checkbox' name='ids[]' lay-skin='primary' value='\$id' /></td>
                    <td class='text-center'><input type='text' class='layui-input displayorder' name='data[\$id][displayorder]' autocomplete='off' value='\$displayorder'></td>
                    <td>\$id</td>
                    <td>\$spacer\$name</td>
                    <td>\$dirname</td>
                    <td class='text-center'>\$letter</td>
                    <td class='text-center'>\$show</td>
                    <td>\$mn_option</td>
                </tr>";
        $data = $tree->getTree($pid, $str);
        return $data ? $data : '';
    }

    /**
     * 树形结构 - array
     * @access public
     * @param int $pid 父栏目ID
     * @return array
     */
    public function getTreeArray($pid = 0)
    {
        $pid = (int)$pid;
        // 查询所有内容
        $result = $this->order(['displayorder' => 'asc', 'id' => 'desc'])->select();
        // 实例化树型类
        $tree = new Tree;
        //设置树型结构所需的数组
        $tree->init(collection($result)->toArray());
        $data = $tree->getTreeArray($pid);
        return $data ? $data : [];
    }

    /**
     * 删除栏目
     * @param   array $ids 栏目id数组
     */
    public function delCategory($ids)
    {
        if (is_array($ids)) {
            foreach ($ids as $id) {
                $this->getId($id);
            }
        } else {
            $this->getId($ids);
        }

        $this->ids && $this->where('id', 'in', $this->ids)->delete();

        $this->repair();
    }

    /**
     * 修复栏目完整数据
     * @access public
     * @return void
     */
    public function repair()
    {
        $this->categorys = $this->getAllCategorys();

        if (is_array($this->categorys)) {
            foreach ($this->categorys as $category) {
                $pids = $this->getPids($category->getAttr('id'));
                $childids = $this->getChildids($category->getAttr('id'));
                $child = is_numeric($childids) ? 0 : 1;
                $pdirname = $this->getPdirname($category->getAttr('id'));
                if ($category->getAttr('pids') != $pids || $category->getAttr('childids') != $childids || $category->getAttr('child') != $child || $category->getAttr('pdirname') != $pdirname) {

                    $category->pids = $pids;
                    $category->child = $child;
                    $category->childids = $childids;
                    $category->pdirname = $pdirname;
                    $category->save();
                }
            }
        }
    }

    /**
     * 所有数据
     * @return array
     */
    public function getAllCategorys()
    {

        $data = [];
        $_data = $this->order('displayorder asc,id asc')->select();
        if (!$_data) {
            return $data;
        }

        foreach ($_data as $t) {
            $data[$t->getAttr('id')] = $t;
        }

        return $data;
    }

    /**
     * 更新缓存
     * @access public
     * @return  void
     */
    public function cache()
    {
        self::setCacheAll();
    }

    /**
     * 获取自己id和子id
     */
    protected function getId($id)
    {

        if (!$id) {
            return NULL;
        }

        $this->ids[$id] = (int)$id;

        $data = $this->where('pid', $id)->field('id')->select();
        if (!$data) {
            return NULL;
        }

        foreach ($data as $t) {
            $this->ids[$t->getAttr('id')] = $t->getAttr('id');
            $this->getId($t->getAttr('id'));
        }
    }

    /**
     * 获取所有父级
     *
     * @param   integer $catid 栏目ID
     * @param   array $pids 父栏目ID
     * @param   integer $n 递归计数
     * @return  string
     */
    protected function getPids($catid, $pids = '', $n = 1)
    {

        if ($n > 5 || !is_array($this->categorys) || !isset($this->categorys[$catid])) {
            return FALSE;
        }

        $pid = $this->categorys[$catid]->getAttr('pid');
        $pids = $pids ? $pid . ',' . $pids : $pid;

        if ($pid) {
            $pids = $this->getPids($pid, $pids, ++$n);
        } else {
            $this->categorys[$catid]->pids = $pids;
        }

        return $pids;
    }

    /**
     * 获取全部子栏目
     *
     * @param   $catid  栏目ID
     * @return  string
     */
    protected function getChildids($catid)
    {

        $childids = $catid;

        if (is_array($this->categorys)) {
            foreach ($this->categorys as $id => $cat) {
                if ($cat->getAttr('pid')
                    && $id != $catid
                    && $cat->getAttr('pid') == $catid) {
                    $childids .= ',' . $this->getChildids($id);
                }
            }
        }

        return $childids;
    }

    /**
     * 上级栏目目录
     *
     * @param   $catid  栏目ID
     * @return  string
     */
    protected function getPdirname($catid)
    {

        if ($this->categorys[$catid]->getAttr('pid') == 0) {
            return '';
        }
        $t = $this->categorys[$catid];
        $pids = $t->getAttr('pids');
        $pids = explode(',', $pids);
        $catdirs = [];
        krsort($pids);

        foreach ($pids as $id) {
            if ($id == 0) {
                continue;
            }
            $catdirs[] = $this->categorys[$id]->getAttr('dirname');
            if ($this->categorys[$id]->getAttr('pdirname') == '') {
                break;
            }
        }

        krsort($catdirs);

        return implode('/', $catdirs) . '/';
    }
}